﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation.Collections;
using Windows.Storage;

namespace Roaming
{
    /// <summary>
    /// Class RoamingObservableDictionary
    /// </summary>

    public class RoamingObservableDictionary : ObservableDictionary<string, string>
    {


        private string _key;
        /// <summary>
        /// Gets or sets the key.
        /// </summary>
        /// <value>The key.</value>
        /// <exception cref="System.ArgumentNullException">value</exception>
        public string Key
        {
            get
            {
                return !string.IsNullOrEmpty(Get("Key")) ? Get("Key") : _key;
            }
            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    throw new ArgumentNullException("value");
                }
                Set("Key", value);
            }
        }
        /// <summary>
        /// The _defer. Used to halt InvokeMapChanged
        /// </summary>
        private bool _defer;
        /// <summary>
        /// Invokes that the dictionary  has changed.
        /// </summary>
        /// <param name="change">The change.</param>
        /// <param name="key">The key.</param>
        public override async void InvokeMapChanged(CollectionChange change, string key)
        {
            if (_container != null && !string.IsNullOrEmpty(key))
            {

                if (!(_container.Values.ContainsKey(key) && string.Equals(Get(key), _container.Values[key])))
                {
                    Debug.WriteLine("Roaming " + key);
                    _container.Values[key] = Get(key);
                }
                else
                {
                    Debug.WriteLine("No need to Roaming " + key);
                }
            }


            if (!_defer)
            {
                Debug.WriteLine("InvokeMapChanged " + this + " => " + change + " - " + key);
                base.InvokeMapChanged(change, key);
            }

        }
        /// <summary>
        /// Initializes a new instance of the <see cref="RoamingObservableDictionary"/> class.
        /// </summary>
        public RoamingObservableDictionary()
        {
            _key = Guid.NewGuid().ToString();

            ApplicationData.Current.DataChanged += Current_DataChanged;
        }

        /// <summary>
        /// method executed when the data changed.See ApplicationData.Current.SignalDataChanged and See <see cref="ApplicationData"/> class.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The args.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        async void Current_DataChanged(ApplicationData sender, object args)
        {
            await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                LoadFrom(Container.Values);
            });
        }
        /// <summary>
        /// Loads from a existing dictionary.
        /// </summary>
        /// <param name="memberwiseclone">The memberwiseclone.</param>
        public void LoadFrom(IDictionary<string, object> memberwiseclone)
        {
            LoadFrom(memberwiseclone.AsEnumerable());
        }

        /// <summary>
        /// Loads from a existing dictionary.
        /// </summary>
        /// <param name="memberwiseclone">The memberwiseclone.</param>
        private void LoadFrom(IEnumerable<KeyValuePair<string, object>> memberwiseclone)
        {
            _defer = true;
            foreach (var item in memberwiseclone)
            {
                this[item.Key] = item.Value + "";
            }
            if (!this.ContainsKey("Key"))
            {
                Key = _key;
            }

            _defer = false;
            InvokeMapChanged(CollectionChange.Reset, "");
        }
        /// <summary>
        /// Loads from.
        /// </summary>
        /// <param name="memberwiseclone">The memberwiseclone.</param>
        public void LoadFrom(IDictionary<string, string> memberwiseclone)
        {
            LoadFrom(memberwiseclone.Select(x => new KeyValuePair<string, object>(x.Key, x.Value + "")));
        }
        /// <summary>
        /// The _container
        /// </summary>
        private ApplicationDataContainer _container;
        /// <summary>
        /// Gets or sets the container used to store the settings
        /// </summary>
        /// <value>The container.</value>
        public ApplicationDataContainer Container
        {
            get
            {
                return _container;
            }
            set
            {
                _container = value;
                if (_container != null)
                {
                    LoadFrom(_container.Values);
                }

            }
        }
        /// <summary>
        /// Gets the specified value for key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>System.String.</returns>
        public string Get(string key)
        {
            if (this.ContainsKey(key))
            {
                return this[key];
            }
            else
            {
                return "";
            }
        }
        /// <summary>
        /// Sets the specified key with to a value.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        public void Set(string key, string value)
        {
            this[key] = value;
        }
    }
}
